home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / editors / emacs / xemacs / xemacs-1.004 / xemacs-1 / xemacs-19.13 / src / faces.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-08-15  |  43.2 KB  |  1,538 lines

  1. /* "Face" primitives
  2.    Copyright (C) 1994 Free Software Foundation, Inc.
  3.    Copyright (C) 1995 Board of Trustees, University of Illinois
  4.    Copyright (C) 1995 Ben Wing
  5.  
  6. This file is part of XEmacs.
  7.  
  8. XEmacs is free software; you can redistribute it and/or modify it
  9. under the terms of the GNU General Public License as published by the
  10. Free Software Foundation; either version 2, or (at your option) any
  11. later version.
  12.  
  13. XEmacs is distributed in the hope that it will be useful, but WITHOUT
  14. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  16. for more details.
  17.  
  18. You should have received a copy of the GNU General Public License
  19. along with XEmacs; see the file COPYING.  If not, write to the Free
  20. Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  21.  
  22. /* Synched up with: Not in FSF. */
  23.  
  24. /* Written by Chuck Thompson and Ben Wing,
  25.    based loosely on old face code by Jamie Zawinski. */
  26.  
  27. #include <config.h>
  28. #include "lisp.h"
  29.  
  30. #include "buffer.h"
  31. #include "device.h"
  32. #include "elhash.h"
  33. #include "extents.h"
  34. #include "faces.h"
  35. #include "frame.h"
  36. #include "glyphs.h"
  37. #include "hash.h"
  38. #include "objects.h"
  39. #include "specifier.h"
  40. #include "window.h"
  41.  
  42. #ifdef HAVE_X_WINDOWS
  43. #include "device-x.h"
  44. #include "frame-x.h"
  45. #include "objects-x.h"
  46. #include "EmacsFrame.h"
  47. #endif /* HAVE_X_WINDOWS */
  48.  
  49. #ifdef HAVE_NEXTSTEP
  50. #include "device-ns.h"
  51. #include "frame-ns.h"
  52. #include "objects-ns.h"
  53. #endif /* HAVE_NEXTSTEP */
  54.  
  55. /* Qfont, Qdoc_string defined in general.c */
  56. Lisp_Object Qface, Qfacep;
  57. Lisp_Object Qforeground, Qbackground, Qdisplay_table;
  58. /* Qhighlight, Qreverse defined in general.c */
  59. Lisp_Object Qbackground_pixmap, Qunderline, Qdim;
  60. Lisp_Object Qblinking;
  61.  
  62. Lisp_Object Qinit_face_from_resources;
  63. Lisp_Object Qinit_frame_faces;
  64. Lisp_Object Qinit_device_faces;
  65. Lisp_Object Qinit_global_faces;
  66. Lisp_Object Qinit_faces;
  67.  
  68. /* These faces are used directly internally.  We use these variables
  69.    to be able to reference them directly and save the overhead of
  70.    calling Ffind_face. */
  71. Lisp_Object Vdefault_face, Vmodeline_face, Vhighlight_face;
  72. Lisp_Object Vleft_margin_face, Vright_margin_face;
  73.  
  74. /* Qdefault, Qhighlight defined in general.c */
  75. Lisp_Object Qmodeline, Qleft_margin, Qright_margin;
  76.  
  77. /* In the old implementation Vface_list was a list of the face names,
  78.    not the faces themselves.  We now distinguish between permanent and
  79.    temporary faces.  Permanent faces are kept in a regular hash table,
  80.    temporary faces in a weak hash table. */
  81. Lisp_Object Vpermanent_faces_cache;
  82. Lisp_Object Vtemporary_faces_cache;
  83.  
  84.  
  85. static Lisp_Object mark_face (Lisp_Object, void (*) (Lisp_Object));
  86. static void print_face (Lisp_Object, Lisp_Object, int);
  87. static int face_equal (Lisp_Object, Lisp_Object, int depth);
  88. static unsigned long face_hash (Lisp_Object obj, int depth);
  89. static int face_getprop (Lisp_Object obj, Lisp_Object prop,
  90.              Lisp_Object *value_out);
  91. static int face_putprop (Lisp_Object obj, Lisp_Object prop, Lisp_Object value);
  92. static int face_remprop (Lisp_Object obj, Lisp_Object prop);
  93. static Lisp_Object face_props (Lisp_Object obj);
  94. DEFINE_LRECORD_IMPLEMENTATION_WITH_PROPS ("face", face,
  95.                       mark_face, print_face, 0, face_equal,
  96.                       face_hash, face_getprop,
  97.                       face_putprop, face_remprop,
  98.                       face_props, struct Lisp_Face);
  99.  
  100. static Lisp_Object
  101. mark_face (Lisp_Object obj, void (*markobj) (Lisp_Object))
  102. {
  103.   struct Lisp_Face *face =  XFACE (obj);
  104.  
  105.   ((markobj) (face->name));
  106.   ((markobj) (face->doc_string));
  107.  
  108.   ((markobj) (face->foreground));
  109.   ((markobj) (face->background));
  110.   ((markobj) (face->font));
  111.   ((markobj) (face->display_table));
  112.   ((markobj) (face->background_pixmap));
  113.   ((markobj) (face->underline));
  114.   ((markobj) (face->highlight));
  115.   ((markobj) (face->dim));
  116.   ((markobj) (face->blinking));
  117.   ((markobj) (face->reverse));
  118.  
  119.   return (face->plist);
  120. }
  121.  
  122. static void
  123. print_face (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
  124. {
  125.   struct Lisp_Face *face = XFACE (obj);
  126.  
  127.   if (print_readably)
  128.     error ("printing unreadable object #<face %s>",
  129.        string_data (XSYMBOL (face->name)->name));
  130.  
  131.   write_c_string ("#<face ", printcharfun);
  132.   print_internal (face->name, printcharfun, 1);
  133.   if (!NILP (face->doc_string))
  134.     {
  135.       write_c_string (" ", printcharfun);
  136.       print_internal (face->doc_string, printcharfun, 1);
  137.     }
  138.   write_c_string (">", printcharfun);
  139. }
  140.  
  141. /* Faces are equal if all of their display attributes are equal.  We
  142.    don't compare names or doc-strings, because that would make equal
  143.    be eq.
  144.  
  145.    This isn't concerned with "unspecified" attributes, that's what
  146.    #'face-differs-from-default-p is for. */
  147. static int
  148. face_equal (Lisp_Object o1, Lisp_Object o2, int depth)
  149. {
  150.   struct Lisp_Face *f1 = XFACE (o1);
  151.   struct Lisp_Face *f2 = XFACE (o2);
  152.  
  153.   depth++;
  154.  
  155.   if (!internal_equal (f1->foreground, f2->foreground, depth) ||
  156.       !internal_equal (f1->background, f2->background, depth) ||
  157.       !internal_equal (f1->font, f2->font, depth) ||
  158.       !internal_equal (f1->display_table, f2->display_table, depth) ||
  159.       !internal_equal (f1->background_pixmap, f2->background_pixmap, depth) ||
  160.       !internal_equal (f1->underline, f2->underline, depth) ||
  161.       !internal_equal (f1->highlight, f2->highlight, depth) ||
  162.       !internal_equal (f1->dim, f2->dim, depth) ||
  163.       !internal_equal (f1->blinking, f2->blinking, depth) ||
  164.       !internal_equal (f1->reverse, f2->reverse, depth) ||
  165.       plists_differ (f1->plist, f2->plist, depth + 1))
  166.     return 0;
  167.  
  168.   return 1;
  169. }
  170.  
  171. static unsigned long
  172. face_hash (Lisp_Object obj, int depth)
  173. {
  174.   struct Lisp_Face *f = XFACE (obj);
  175.  
  176.   depth++;
  177.  
  178.   /* No need to hash all of the elements; that would take too long.
  179.      Just hash the most common ones. */
  180.   return HASH3 (internal_hash (f->foreground, depth),
  181.         internal_hash (f->background, depth),
  182.         internal_hash (f->font, depth));
  183. }
  184.  
  185. static int
  186. face_getprop (Lisp_Object obj, Lisp_Object prop, Lisp_Object *value_out)
  187. {
  188.   struct Lisp_Face *f = XFACE (obj);
  189.  
  190. #define FROB(propprop)                             \
  191. do {                                    \
  192.   if (EQ (prop, Q##propprop))                        \
  193.     {                                    \
  194.       *value_out = f->propprop;                        \
  195.       return 1;                                \
  196.     }                                    \
  197. } while (0)
  198.  
  199.   FROB (foreground);
  200.   FROB (background);
  201.   FROB (font);
  202.   FROB (display_table);
  203.   FROB (background_pixmap);
  204.   FROB (underline);
  205.   FROB (highlight);
  206.   FROB (dim);
  207.   FROB (blinking);
  208.   FROB (reverse);
  209.  
  210. #undef FROB
  211.  
  212.   return internal_getf (f->plist, prop, value_out);
  213. }
  214.  
  215. static int
  216. face_putprop (Lisp_Object obj, Lisp_Object prop, Lisp_Object value)
  217. {
  218.   struct Lisp_Face *f = XFACE (obj);
  219.  
  220. #define FROB(propprop)                             \
  221. do {                                    \
  222.   if (EQ (prop, Q##propprop))                        \
  223.     return 0;                                \
  224. } while (0)
  225.  
  226.   FROB (foreground);
  227.   FROB (background);
  228.   FROB (font);
  229.   FROB (display_table);
  230.   FROB (background_pixmap);
  231.   FROB (underline);
  232.   FROB (highlight);
  233.   FROB (dim);
  234.   FROB (blinking);
  235.   FROB (reverse);
  236.  
  237. #undef FROB
  238.  
  239.   if (EQ (prop, Qdoc_string))
  240.     {
  241.       if (!NILP (value))
  242.     CHECK_STRING (value, 0);
  243.       f->doc_string = value;
  244.       return 1;
  245.     }
  246.  
  247.   internal_putf (&f->plist, prop, value);
  248.   return 1;
  249. }
  250.  
  251. static int
  252. face_remprop (Lisp_Object obj, Lisp_Object prop)
  253. {
  254.   struct Lisp_Face *f = XFACE (obj);
  255.  
  256. #define FROB(propprop)                             \
  257. do {                                    \
  258.   if (EQ (prop, Q##propprop))                        \
  259.     return -1;                                \
  260. } while (0)
  261.  
  262.   FROB (foreground);
  263.   FROB (background);
  264.   FROB (font);
  265.   FROB (display_table);
  266.   FROB (background_pixmap);
  267.   FROB (underline);
  268.   FROB (highlight);
  269.   FROB (dim);
  270.   FROB (blinking);
  271.   FROB (reverse);
  272.  
  273. #undef FROB
  274.  
  275.   if (EQ (prop, Qdoc_string))
  276.     {
  277.       f->doc_string = Qnil;
  278.       return 1;
  279.     }
  280.  
  281.   return internal_remprop (&f->plist, prop);
  282. }
  283.  
  284. static Lisp_Object
  285. face_props (Lisp_Object obj)
  286. {
  287.   struct Lisp_Face *f = XFACE (obj);
  288.   Lisp_Object result = Qnil;
  289.  
  290. #define FROB(propprop)                             \
  291. do {                                    \
  292.   result = Fcons (f->propprop, Fcons (Q##propprop, result));        \
  293. } while (0)
  294.  
  295.   /* backwards order; we reverse it below */
  296.   FROB (reverse);
  297.   FROB (blinking);
  298.   FROB (dim);
  299.   FROB (highlight);
  300.   FROB (underline);
  301.   FROB (background_pixmap);
  302.   FROB (display_table);
  303.   FROB (font);
  304.   FROB (background);
  305.   FROB (foreground);
  306.  
  307. #undef FROB
  308.   return nconc2 (Fnreverse (result), Fcopy_sequence (f->plist));
  309. }
  310.  
  311.  
  312. /*****************************************************************************
  313.  utility functions
  314.  ****************************************************************************/
  315.  
  316. static void
  317. reset_face (struct Lisp_Face *f)
  318. {
  319.   f->name = Qnil;
  320.   f->doc_string = Qnil;
  321.   f->dirty = 0;
  322.   f->foreground = Qnil;
  323.   f->background = Qnil;
  324.   f->font = Qnil;
  325.   f->display_table = Qnil;
  326.   f->background_pixmap = Qnil;
  327.   f->underline = Qnil;
  328.   f->highlight = Qnil;
  329.   f->dim = Qnil;
  330.   f->blinking = Qnil;
  331.   f->reverse = Qnil;
  332.   f->plist = Qnil;
  333. }
  334.  
  335. static struct Lisp_Face *
  336. allocate_face (void)
  337. {
  338.   struct Lisp_Face *result =
  339.     alloc_lcrecord (sizeof (struct Lisp_Face), lrecord_face);
  340.  
  341.   reset_face (result);
  342.   return result;
  343. }
  344.  
  345.  
  346. /* We store the faces in hash tables with the names as the key and the
  347.    actual face object as the value.  Occasionally we need to use them
  348.    in a list format.  These routines provide us with that. */
  349. struct face_list_closure
  350. {
  351.   Lisp_Object *face_list;
  352. };
  353.  
  354. static void
  355. add_face_to_list_mapper (CONST void *hash_key, void *hash_contents,
  356.              void *face_list_closure)
  357. {
  358.   /* This function can GC */
  359.   Lisp_Object key, contents;
  360.   Lisp_Object *face_list;
  361.   struct face_list_closure *fcl = face_list_closure;
  362.   CVOID_TO_LISP (key, hash_key);
  363.   VOID_TO_LISP (contents, hash_contents);
  364.   face_list = fcl->face_list;
  365.  
  366.   *face_list = Fcons (XFACE (contents)->name, *face_list);
  367. }
  368.  
  369. static Lisp_Object
  370. faces_list_internal (Lisp_Object list)
  371. {
  372.   Lisp_Object face_list = Qnil;
  373.   struct gcpro gcpro1;
  374.   struct face_list_closure face_list_closure;
  375.  
  376.   GCPRO1 (face_list);
  377.   face_list_closure.face_list = &face_list;
  378.   elisp_maphash (add_face_to_list_mapper, list, &face_list_closure);
  379.   UNGCPRO;
  380.  
  381.   return face_list;
  382. }
  383.  
  384. static Lisp_Object
  385. permanent_faces_list (void)
  386. {
  387.   return faces_list_internal (Vpermanent_faces_cache);
  388. }
  389.  
  390. static Lisp_Object
  391. temporary_faces_list (void)
  392. {
  393.   return faces_list_internal (Vtemporary_faces_cache);
  394. }
  395.  
  396.  
  397. static void
  398. mark_face_as_clean_mapper (CONST void *hash_key, void *hash_contents,
  399.                void *flag_closure)
  400. {
  401.   /* This function can GC */
  402.   Lisp_Object key, contents;
  403.   int *flag = flag_closure;
  404.   CVOID_TO_LISP (key, hash_key);
  405.   VOID_TO_LISP (contents, hash_contents);
  406.   XFACE (contents)->dirty = *flag;
  407. }
  408.  
  409. static void
  410. mark_all_faces_internal (int flag)
  411. {
  412.   elisp_maphash (mark_face_as_clean_mapper, Vpermanent_faces_cache, &flag);
  413.   elisp_maphash (mark_face_as_clean_mapper, Vtemporary_faces_cache, &flag);
  414. }
  415.  
  416. void
  417. mark_all_faces_as_clean (void)
  418. {
  419.   mark_all_faces_internal (0);
  420. }
  421.  
  422. /* #### OBSOLETE ME, PLEASE.  Maybe.  Maybe this is just as good as
  423.    any other solution. */
  424. struct face_inheritance_closure
  425. {
  426.   Lisp_Object face;
  427.   Lisp_Object property;
  428. };
  429.  
  430. static void
  431. update_inheritance_mapper_internal (Lisp_Object cur_face,
  432.                     Lisp_Object inh_face,
  433.                     Lisp_Object property)
  434. {
  435.   /* #### fix this function */
  436.   Lisp_Object elt = Qnil;
  437.   struct gcpro gcpro1;
  438.  
  439.   GCPRO1 (elt);
  440.  
  441.   for (elt = FACE_PROPERTY_SPEC_LIST (cur_face, property, Qall);
  442.        !NILP (elt);
  443.        elt = XCDR (elt))
  444.     {
  445.       Lisp_Object locale, values;
  446.  
  447.       locale = XCAR (XCAR (elt));
  448.       values = XCDR (XCAR (elt));
  449.  
  450.       for (; !NILP (values); values = XCDR (values))
  451.     {
  452.       Lisp_Object tag = XCAR (XCAR (values));
  453.       Lisp_Object value = XCDR (XCAR (values));
  454.       if (VECTORP (value) && XVECTOR (value)->size)
  455.         {
  456.           if (EQ (Ffind_face (vector_data (XVECTOR (value))[0]), inh_face))
  457.         {
  458.           /* #### This should probably be changed.  We just want
  459.              to mark the face as dirty and reset its specifier
  460.              instance list. */
  461.           SET_FACE_PROPERTY (cur_face, property, value, locale, tag,
  462.                      Qnil);
  463.         }
  464.         }
  465.     }
  466.     }
  467.  
  468.   UNGCPRO;
  469. }
  470.  
  471. static void
  472. update_face_inheritance_mapper (CONST void *hash_key, void *hash_contents,
  473.                 void *face_inheritance_closure)
  474. {
  475.   Lisp_Object key, contents;
  476.   struct face_inheritance_closure *fcl = face_inheritance_closure;
  477.  
  478.   CVOID_TO_LISP (key, hash_key);
  479.   VOID_TO_LISP (contents, hash_contents);
  480.  
  481.   if (EQ (fcl->property, Qfont))
  482.     {
  483.       update_inheritance_mapper_internal (contents, fcl->face, Qfont);
  484.     }
  485.   else if (EQ (fcl->property, Qforeground)
  486.        || EQ (fcl->property, Qbackground))
  487.     {
  488.       update_inheritance_mapper_internal (contents, fcl->face, Qforeground);
  489.       update_inheritance_mapper_internal (contents, fcl->face, Qbackground);
  490.     }
  491.   else if (EQ (fcl->property, Qunderline)
  492.        || EQ (fcl->property, Qhighlight)
  493.        || EQ (fcl->property, Qdim)
  494.        || EQ (fcl->property, Qblinking)
  495.        || EQ (fcl->property, Qreverse))
  496.     {
  497.       update_inheritance_mapper_internal (contents, fcl->face, Qunderline);
  498.       update_inheritance_mapper_internal (contents, fcl->face, Qhighlight);
  499.       update_inheritance_mapper_internal (contents, fcl->face, Qdim);
  500.       update_inheritance_mapper_internal (contents, fcl->face, Qblinking);
  501.       update_inheritance_mapper_internal (contents, fcl->face, Qreverse);
  502.     }
  503. }
  504.  
  505. static void
  506. update_faces_inheritance (Lisp_Object face, Lisp_Object property)
  507. {
  508.   struct face_inheritance_closure face_inheritance_closure;
  509.   struct gcpro gcpro1, gcpro2;
  510.  
  511.   GCPRO2 (face, property);
  512.   face_inheritance_closure.face = face;
  513.   face_inheritance_closure.property = property;
  514.  
  515.   elisp_maphash (update_face_inheritance_mapper, Vpermanent_faces_cache,
  516.          &face_inheritance_closure);
  517.   elisp_maphash (update_face_inheritance_mapper, Vtemporary_faces_cache,
  518.          &face_inheritance_closure);
  519.  
  520.   UNGCPRO;
  521. }
  522.  
  523.  
  524. DEFUN ("facep", Ffacep, Sfacep, 1, 1, 0,
  525.        "Return non-nil if OBJECT is a face.")
  526.      (object)
  527.      Lisp_Object object;
  528. {
  529.   return (FACEP (object) ? Qt : Qnil);
  530. }
  531.  
  532. DEFUN ("find-face", Ffind_face, Sfind_face, 1, 1, 0,
  533.        "Retrieve the face of the given name.\n\
  534. If FACE-OR-NAME is a face object, it is simply returned.\n\
  535. Otherwise, FACE-OR-NAME should be a symbol.  If there is no such face,\n\
  536. nil is returned.  Otherwise the associated face object is returned.")
  537.      (face_or_name)
  538.      Lisp_Object face_or_name;
  539. {
  540.   Lisp_Object retval;
  541.  
  542.   if (FACEP (face_or_name))
  543.     return face_or_name;
  544.   CHECK_SYMBOL (face_or_name, 0);
  545.  
  546.   /* Check if the name represents a permanent face. */
  547.   retval = Fgethash (face_or_name, Vpermanent_faces_cache, Qnil);
  548.   if (!NILP (retval))
  549.     return retval;
  550.  
  551.   /* Check if the name represents a temporary face. */
  552.   return Fgethash (face_or_name, Vtemporary_faces_cache, Qnil);
  553. }
  554.  
  555. DEFUN ("get-face", Fget_face, Sget_face, 1, 1, 0,
  556.        "Retrieve the face of the given name.\n\
  557. Same as `find-face' except an error is signalled if there is no such\n\
  558. face instead of returning nil.")
  559.      (name)
  560.      Lisp_Object name;
  561. {
  562.   Lisp_Object face = Ffind_face (name);
  563.  
  564.   if (NILP (face))
  565.     signal_simple_error ("No such face", name);
  566.   return face;
  567. }
  568.  
  569. DEFUN ("face-name", Fface_name, Sface_name, 1, 1, 0,
  570.        "Return the name of the given face.")
  571.      (face)
  572.      Lisp_Object face;
  573. {
  574.   return (XFACE (Fget_face (face))->name);
  575. }
  576.  
  577. void
  578. face_font_metric_info (Lisp_Object face, Lisp_Object domain,
  579.                struct font_metric_info *fm)
  580. {
  581.   struct device *d = XDEVICE (DFW_DEVICE (domain));
  582.  
  583.   DEVMETH (d, font_metric_info, (d, FACE_FONT (face, domain),
  584.                  fm));
  585. }
  586.  
  587. /* These values are retrieved so often that we make a special
  588.    function.
  589.  
  590.    #### Should this perhaps look in the face-cache-element cache
  591.    for the domain, esp. if it is a window (as is usually the case)? */
  592.  
  593. void
  594. default_face_height_and_width (Lisp_Object domain,
  595.                    int *height, int *width)
  596. {
  597.   struct device *d = XDEVICE (DFW_DEVICE (domain));
  598.   struct font_metric_info fm;
  599.  
  600.   DEVMETH (d, font_metric_info, (d, FACE_FONT (Vdefault_face, domain),
  601.                  &fm));
  602.   *height = fm.height;
  603.   *width = fm.width;
  604. }
  605.  
  606. DEFUN ("face-ascent", Fface_ascent, Sface_ascent, 1, 2, 0,
  607.        "Return the ascent portion of the FACE's height in the given DOMAIN.\n\
  608. If DOMAIN is nil, it will be determined from the selected window.")
  609.      (face, domain)
  610.      Lisp_Object face, domain;
  611. {
  612.   struct font_metric_info fm;
  613.  
  614.   face = Fget_face (face);
  615.   domain = decode_domain (domain);
  616.  
  617.   face_font_metric_info (face, domain, &fm);
  618.   return (make_number (fm.ascent));
  619. }
  620.  
  621. DEFUN ("face-descent", Fface_descent, Sface_descent, 1, 2, 0,
  622.        "Return the descent portion of the FACE's height in the given DOMAIN.\n\
  623. If DOMAIN is nil, it will be determined from the selected window.")
  624.      (face, domain)
  625.      Lisp_Object face, domain;
  626. {
  627.   struct font_metric_info fm;
  628.  
  629.   face = Fget_face (face);
  630.   domain = decode_domain (domain);
  631.  
  632.   face_font_metric_info (face, domain, &fm);
  633.   return (make_number (fm.descent));
  634. }
  635.  
  636. DEFUN ("face-width", Fface_width, Sface_width, 1, 2, 0,
  637.        "Return the width of FACE in the given DOMAIN.\n\
  638. If DOMAIN is nil, it will be determined from the selected window.")
  639.      (face, domain)
  640.      Lisp_Object face, domain;
  641. {
  642.   struct font_metric_info fm;
  643.  
  644.   face = Fget_face (face);
  645.   domain = decode_domain (domain);
  646.  
  647.   face_font_metric_info (face, domain, &fm);
  648.   return (make_number (fm.width));
  649. }
  650.  
  651. DEFUN ("face-list", Fface_list, Sface_list, 0, 1, 0,
  652.        "Return a list of the names of all defined faces.\n\
  653. If TEMPORARY is nil, only the permanent faces are included.\n\
  654. If it is t, only the temporary faces are included.  If it is any\n\
  655. other non-nil value both permanent and temporary are included.")
  656.      (temporary)
  657.      Lisp_Object temporary;
  658. {
  659.   Lisp_Object face_list = Qnil;
  660.  
  661.   /* Added the permanent faces, if requested. */
  662.   if (NILP (temporary) || !EQ (Qt, temporary))
  663.     face_list = permanent_faces_list ();
  664.  
  665.   if (!NILP (temporary))
  666.     {
  667.       struct gcpro gcpro1;
  668.       GCPRO1 (face_list);
  669.       face_list = nconc2 (face_list, temporary_faces_list ());
  670.       UNGCPRO;
  671.     }
  672.  
  673.   return face_list;
  674. }
  675.  
  676. DEFUN ("extent-face", Fextent_face, Sextent_face, 1, 1, 0,
  677.        "Return the name of the face in which EXTENT is displayed, or nil\n\
  678. if the extent's face is unspecified.")
  679.      (extent)
  680.      Lisp_Object extent;
  681. {
  682.   CHECK_EXTENT (extent, 0);
  683.  
  684.   if (NILP (extent_face (XEXTENT (extent))))
  685.     return Qnil;
  686.   else
  687.     return (XFACE (extent_face (XEXTENT (extent)))->name);
  688. }
  689.  
  690. DEFUN ("set-extent-face", Fset_extent_face, Sset_extent_face, 2, 2, 0,
  691.        "Make the given EXTENT have the graphic attributes specified by FACE.")
  692.      (extent, face)
  693.      Lisp_Object extent, face;
  694. {
  695.   EXTENT e;
  696.  
  697.   CHECK_EXTENT (extent, 0);
  698.   e = XEXTENT (extent);
  699.  
  700.   if (!NILP (face))
  701.     face = Fget_face (face);
  702.  
  703.   set_extent_face (e, face);
  704.  
  705.   return face;
  706. }
  707.  
  708. DEFUN ("make-face", Fmake_face, Smake_face, 1, 3, 0,
  709.        "Defines and returns a new FACE described by DOC-STRING.\n\
  710. You can modify the font, color, etc of a face with the set-face- functions.\n\
  711. If the face already exists, it is unmodified.\n\
  712. If TEMPORARY is non-nil, this face will cease to exist if not in use.")
  713.      (name, doc_string, temporary)
  714.      Lisp_Object name, doc_string, temporary;
  715. {
  716.   /* This function can GC if initialized is non-zero */
  717.   struct Lisp_Face *f;
  718.   Lisp_Object face;
  719.  
  720.   CHECK_SYMBOL (name, 0);
  721.   if (!NILP (doc_string))
  722.     CHECK_STRING (doc_string, 0);
  723.  
  724.   face = Ffind_face (name);
  725.   if (!NILP (face))
  726.     return face;
  727.  
  728.   f = allocate_face ();
  729.   XSETFACE (face, f);
  730.  
  731.   f->name = name;
  732.   f->doc_string = doc_string;
  733.   f->foreground = Fmake_specifier (Qcolor);
  734.   set_color_attached_to (f->foreground, face, Qforeground);
  735.   f->background = Fmake_specifier (Qcolor);
  736.   set_color_attached_to (f->background, face, Qbackground);
  737.   f->font = Fmake_specifier (Qfont);
  738.   set_font_attached_to (f->font, face, Qfont);
  739.   f->background_pixmap = Fmake_specifier (Qimage);
  740.   set_image_attached_to (f->background_pixmap, face, Qbackground_pixmap);
  741.   /* #### need a special display-table specifier */
  742.   f->display_table = Fmake_specifier (Qgeneric);
  743.   f->underline = Fmake_specifier (Qface_boolean);
  744.   set_face_boolean_attached_to (f->underline, face, Qunderline);
  745.   f->highlight = Fmake_specifier (Qface_boolean);
  746.   set_face_boolean_attached_to (f->highlight, face, Qhighlight);
  747.   f->dim = Fmake_specifier (Qface_boolean);
  748.   set_face_boolean_attached_to (f->dim, face, Qdim);
  749.   f->blinking = Fmake_specifier (Qface_boolean);
  750.   set_face_boolean_attached_to (f->blinking, face, Qblinking);
  751.   f->reverse = Fmake_specifier (Qface_boolean);
  752.   set_face_boolean_attached_to (f->reverse, face, Qreverse);
  753.   if (!NILP (Vdefault_face))
  754.     {
  755.       /* If the default face has already been created, set it as
  756.      the default fallback specifier for all the specifiers we
  757.      just created.  This implements the standard "all faces
  758.      inherit from default" behavior. */
  759.       set_specifier_fallback (f->foreground,
  760.                  Fget (Vdefault_face, Qforeground, Qunbound));
  761.       set_specifier_fallback (f->background,
  762.                  Fget (Vdefault_face, Qbackground, Qunbound));
  763.       set_specifier_fallback (f->font,
  764.                  Fget (Vdefault_face, Qfont, Qunbound));
  765.       set_specifier_fallback (f->background_pixmap,
  766.                  Fget (Vdefault_face, Qbackground_pixmap,
  767.                    Qunbound));
  768.       set_specifier_fallback (f->display_table,
  769.                  Fget (Vdefault_face, Qdisplay_table, Qunbound));
  770.       set_specifier_fallback (f->underline,
  771.                  Fget (Vdefault_face, Qunderline, Qunbound));
  772.       set_specifier_fallback (f->highlight,
  773.                  Fget (Vdefault_face, Qhighlight, Qunbound));
  774.       set_specifier_fallback (f->dim,
  775.                  Fget (Vdefault_face, Qdim, Qunbound));
  776.       set_specifier_fallback (f->blinking,
  777.                  Fget (Vdefault_face, Qblinking, Qunbound));
  778.       set_specifier_fallback (f->reverse,
  779.                  Fget (Vdefault_face, Qreverse, Qunbound));
  780.     }
  781.  
  782.   /* Add the face to the appropriate list. */
  783.   if (NILP (temporary))
  784.     Fputhash (name, face, Vpermanent_faces_cache);
  785.   else
  786.     Fputhash (name, face, Vtemporary_faces_cache);
  787.  
  788.   if (initialized)
  789.     {
  790.       struct gcpro gcpro1, gcpro2;
  791.  
  792.       GCPRO2 (name, face);
  793.       call1 (Qinit_face_from_resources, name);
  794.       UNGCPRO;
  795.     }
  796.  
  797.   return face;
  798. }
  799.  
  800.  
  801. /*****************************************************************************
  802.  initialization code
  803.  ****************************************************************************/
  804.  
  805. void
  806. init_global_faces (struct device *d)
  807. {
  808.   /* When making the initial terminal device, there is no Lisp code
  809.      loaded, so we can't do this. */
  810.   if (initialized)
  811.     {
  812.       call_critical_lisp_code (d, Qinit_global_faces, Qnil);
  813.     }
  814. }
  815.  
  816. void
  817. init_device_faces (struct device *d)
  818. {
  819.   /* When making the initial terminal device, there is no Lisp code
  820.      loaded, so we can't do this. */
  821.   if (initialized)
  822.     {
  823.       Lisp_Object tdevice;
  824.       XSETDEVICE (tdevice, d);
  825.       call_critical_lisp_code (d, Qinit_device_faces, tdevice);
  826.     }
  827. }
  828.  
  829. void
  830. init_frame_faces (struct frame *frm)
  831. {
  832.   /* When making the initial terminal device, there is no Lisp code
  833.      loaded, so we can't do this. */
  834.   if (initialized)
  835.     {
  836.       Lisp_Object tframe;
  837.       XSETFRAME (tframe, frm);
  838.  
  839.       /* DO NOT change the selected frame here.  If the debugger goes off
  840.          it will try and display on the frame being created, but it is not
  841.          ready for that yet and a horrible death will occur.  Any random
  842.          code depending on the selected-frame as an implicit arg should be
  843.          tracked down and shot.  For the benefit of the one known,
  844.          xpm-color-symbols, make-frame sets the variable
  845.          Vframe_being_created to the frame it is making and sets it to nil
  846.          when done.  Internal functions that this could trigger which are
  847.          currently depending on selected-frame should use this instead.  It
  848.          is not currently visible at the lisp level. */
  849.       call_critical_lisp_code (XDEVICE (FRAME_DEVICE (frm)),
  850.                    Qinit_frame_faces, tframe);
  851.     }
  852. }
  853.  
  854.  
  855. /*****************************************************************************
  856.  face cache element functions
  857.  ****************************************************************************/
  858. void
  859. mark_face_cache_elements (face_cache_element_dynarr *elements,
  860.               void (*markobj) (Lisp_Object))
  861. {
  862.   int elt;
  863.  
  864.   if (!elements)
  865.     return;
  866.  
  867.   for (elt = 0; elt < Dynarr_length (elements); elt++)
  868.     {
  869.       struct face_cache_element *inst = Dynarr_atp (elements, elt);
  870.  
  871.       ((markobj) (inst->face));
  872.       ((markobj) (inst->foreground));
  873.       ((markobj) (inst->background));
  874.       ((markobj) (inst->font));
  875.       ((markobj) (inst->display_table));
  876.       ((markobj) (inst->background_pixmap));
  877.     }
  878. }
  879.  
  880. static void
  881. update_face_cache_element_data (struct window *w, Lisp_Object face,
  882.                 struct face_cache_element *cachel)
  883. {
  884.   if (XFACE (face)->dirty || UNBOUNDP (cachel->face))
  885.     {
  886.       int default_face = EQ (face, Vdefault_face);
  887.       Lisp_Object window = Qnil;
  888.  
  889.       XSETWINDOW (window, w);
  890.       cachel->face = face;
  891.  
  892.       /* We normally only set the _specified flags if the value was
  893.          actually bound.  The exception is for the default face where
  894.          we always set it since it is the ultimate fallback. */
  895.  
  896. #define FROB(field)                            \
  897.   do {                                    \
  898.     Lisp_Object new_val = FACE_PROPERTY_INSTANCE (face, Q##field, window, 1); \
  899.     int bound = 1;                            \
  900.     if (UNBOUNDP (new_val))                        \
  901.       {                                    \
  902.     bound = 0;                            \
  903.     new_val = FACE_PROPERTY_INSTANCE (face, Q##field, window, 0);    \
  904.       }                                    \
  905.     if (!EQ (new_val, cachel->field))                    \
  906.       {                                    \
  907.     cachel->field = new_val;                    \
  908.     cachel->dirty = 1;                        \
  909.       }                                    \
  910.     cachel->field##_specified = (bound || default_face);        \
  911.   } while (0)
  912.  
  913.       FROB (foreground);
  914.       FROB (background);
  915.       FROB (font);
  916.       FROB (display_table);
  917.       FROB (background_pixmap);
  918. #undef FROB
  919.  
  920. #define FROB(field)                            \
  921.   do {                                    \
  922.     Lisp_Object new_val = FACE_PROPERTY_INSTANCE (face, Q##field, window, 1); \
  923.     int bound = 1;                            \
  924.     int new_val_int;                            \
  925.     if (UNBOUNDP (new_val))                        \
  926.       {                                    \
  927.     bound = 0;                            \
  928.     new_val = FACE_PROPERTY_INSTANCE (face, Q##field, window, 0);    \
  929.       }                                    \
  930.     new_val_int = EQ (new_val, Qt);                    \
  931.     if (cachel->field != new_val_int)                    \
  932.       {                                    \
  933.     cachel->field = new_val_int;                    \
  934.     cachel->dirty = 1;                        \
  935.       }                                    \
  936.     cachel->field##_specified = bound;                    \
  937.   } while (0)
  938.  
  939.       FROB (underline);
  940.       FROB (highlight);
  941.       FROB (dim);
  942.       FROB (reverse);
  943.       FROB (blinking);
  944. #undef FROB
  945.     }
  946.  
  947.   cachel->updated = 1;
  948. }
  949.  
  950. static void
  951. merge_face_cache_element_data (struct window *w, face_index findex,
  952.                    struct face_cache_element *cachel)
  953. {
  954. #define FINDEX_FIELD(field)                        \
  955.   Dynarr_atp (w->face_cache_elements, findex)->field
  956.  
  957. #define FROB(field)                            \
  958.   do {                                    \
  959.     if (!cachel->field##_specified && FINDEX_FIELD (field##_specified))    \
  960.       {                                    \
  961.     cachel->field = FINDEX_FIELD (field);                \
  962.     cachel->field##_specified = 1;                    \
  963.     cachel->dirty = 1;                        \
  964.       }                                    \
  965.   } while (0)
  966.  
  967.   FROB (foreground);
  968.   FROB (background);
  969.   FROB (font);
  970.   FROB (display_table);
  971.   FROB (background_pixmap);
  972.   FROB (underline);
  973.   FROB (highlight);
  974.   FROB (dim);
  975.   FROB (reverse);
  976.   FROB (blinking);
  977. #undef FROB
  978. #undef FINDEX_FIELD
  979.  
  980.   cachel->updated = 1;
  981. }
  982.  
  983. static void
  984. reset_face_cache_element (struct face_cache_element *inst)
  985. {
  986.   memset (inst, 0, sizeof (struct face_cache_element));
  987.   inst->face = Qunbound;
  988.   inst->foreground = Qunbound;
  989.   inst->background = Qunbound;
  990.   inst->font = Qunbound;
  991.   inst->display_table = Qunbound;
  992.   inst->background_pixmap = Qunbound;
  993. }
  994.  
  995. static void
  996. add_face_cache_element (struct window *w, Lisp_Object face)
  997. {
  998.   struct face_cache_element new_cachel;
  999.  
  1000.   reset_face_cache_element (&new_cachel);
  1001.   update_face_cache_element_data (w, face, &new_cachel);
  1002.   Dynarr_add (w->face_cache_elements, new_cachel);
  1003. }
  1004.  
  1005. face_index
  1006. get_builtin_face_cache_index (struct window *w, Lisp_Object face)
  1007. {
  1008.   int elt;
  1009.  
  1010.   if (noninteractive)
  1011.     return 0;
  1012.  
  1013.   for (elt = 0; elt < Dynarr_length (w->face_cache_elements); elt++)
  1014.     {
  1015.       struct face_cache_element *cachel =
  1016.     Dynarr_atp (w->face_cache_elements, elt);
  1017.  
  1018.       if (EQ (cachel->face, face))
  1019.     {
  1020.       if (!cachel->updated)
  1021.         update_face_cache_element_data (w, face, cachel);
  1022.       return elt;
  1023.     }
  1024.     }
  1025.  
  1026.   /* If we didn't find the face, add it and then return its index. */
  1027.   add_face_cache_element (w, face);
  1028.   return elt;
  1029. }
  1030.  
  1031. void
  1032. reset_face_cache_elements (struct window *w)
  1033. {
  1034.   /* #### Not initialized in batch mode for the stream device. */
  1035.   if (w->face_cache_elements)
  1036.     {
  1037.       Dynarr_reset (w->face_cache_elements);
  1038.       get_builtin_face_cache_index (w, Vdefault_face);
  1039.       get_builtin_face_cache_index (w, Vmodeline_face);
  1040.       XFRAME (w->frame)->window_face_cache_reset = 1;
  1041.     }
  1042. }
  1043.  
  1044. void
  1045. mark_face_cache_elements_as_clean (struct window *w)
  1046. {
  1047.   int elt;
  1048.  
  1049.   for (elt = 0; elt < Dynarr_length (w->face_cache_elements); elt++)
  1050.     Dynarr_atp (w->face_cache_elements, elt)->dirty = 0;
  1051. }
  1052.  
  1053. void
  1054. mark_face_cache_elements_as_not_updated (struct window *w)
  1055. {
  1056.   int elt;
  1057.  
  1058.   for (elt = 0; elt < Dynarr_length (w->face_cache_elements); elt++)
  1059.     Dynarr_atp (w->face_cache_elements, elt)->updated = 0;
  1060. }
  1061.  
  1062. static int
  1063. compare_face_cache_elements (struct face_cache_element *cachel1,
  1064.                  struct face_cache_element *cachel2)
  1065. {
  1066.   if (EQ (cachel1->foreground, cachel2->foreground)
  1067.       && EQ (cachel1->background, cachel2->background)
  1068.       && EQ (cachel1->font, cachel2->font)
  1069.       && EQ (cachel1->display_table, cachel2->display_table)
  1070.       && EQ (cachel1->background_pixmap, cachel2->background_pixmap)
  1071.       && cachel1->underline == cachel2->underline
  1072.       && cachel1->highlight == cachel2->highlight
  1073.       && cachel1->dim == cachel2->dim
  1074.       && cachel1->blinking == cachel2->blinking
  1075.       && cachel1->reverse == cachel2->reverse)
  1076.     return 1;
  1077.   else
  1078.     return 0;
  1079. }
  1080.  
  1081.  
  1082. /*****************************************************************************
  1083.  merged face functions
  1084.  ****************************************************************************/
  1085. static face_index
  1086. get_merged_face_element_index (struct window *w,
  1087.                    struct face_cache_element *merged_inst)
  1088. {
  1089.   int elt;
  1090.   int cache_size = Dynarr_length (w->face_cache_elements);
  1091.  
  1092.   for (elt = 0; elt < cache_size; elt++)
  1093.     {
  1094.       struct face_cache_element *inst =
  1095.     Dynarr_atp (w->face_cache_elements, elt);
  1096.  
  1097.       /* Do not compare the face names.  Merged elements will have it
  1098.          as nil and this would cause false positives.  Also, by doing
  1099.          it this way if a merged instance happens to match a builtin
  1100.          face instance, we'll still return it.  Why add two identical
  1101.          instances? */
  1102.       if (compare_face_cache_elements (inst, merged_inst))
  1103.     return elt;
  1104.     }
  1105.  
  1106.   /* We didn't find it so add this instance to the cache. */
  1107.   merged_inst->updated = 1;
  1108.   merged_inst->dirty = 1;
  1109.   Dynarr_add (w->face_cache_elements, *merged_inst);
  1110.   return cache_size;
  1111. }
  1112.  
  1113. face_index
  1114. get_extent_fragment_face_cache_index (struct window *w,
  1115.                       struct extent_fragment *ef,
  1116.                       EXTENT dummy_lhe_extent)
  1117. {
  1118.   struct face_cache_element cachel;
  1119.   int len = Dynarr_length (ef->extents);
  1120.   face_index findex;
  1121.  
  1122.   /* Optimize the default case. */
  1123.   if (len == 0)
  1124.     return DEFAULT_INDEX;
  1125.   else
  1126.     {
  1127.       int i;
  1128.       Lisp_Object window = Qnil;
  1129.       XSETWINDOW (window, w);
  1130.  
  1131.       /* Merge the faces of the extents together in order.
  1132.  
  1133.      Remember that one of the extents in the list might be our dummy
  1134.      extent representing the highlighting that is attached to some other
  1135.      extent that is currently mouse-highlighted.  When an extent is
  1136.      mouse-highlighted, it is as if there are two extents there, of
  1137.      potentially different priorities: the extent being highlighted, with
  1138.      whatever face and priority it has; and an ephemeral extent in the
  1139.      `highlight' face with `mouse-highlight-priority'.
  1140.        */
  1141.  
  1142.       reset_face_cache_element (&cachel);
  1143.  
  1144.       for (i = len - 1; i >= 0; i--)
  1145.     {
  1146.       EXTENT current = Dynarr_at (ef->extents, i);
  1147.  
  1148.       if (current == dummy_lhe_extent)
  1149.         {
  1150.           /* this isn't a real extent; use the highlight face. */
  1151.           findex = get_builtin_face_cache_index (w, Vhighlight_face);
  1152.           merge_face_cache_element_data (w, findex, &cachel);
  1153.         }
  1154.       else if (!NILP (extent_face (current)))
  1155.         {
  1156.           findex = get_builtin_face_cache_index (w, extent_face (current));
  1157.           merge_face_cache_element_data (w, findex, &cachel);
  1158.         }
  1159.     }
  1160.  
  1161.       /* Now finally merge in the default face. */
  1162.       findex = get_builtin_face_cache_index (w, Vdefault_face);
  1163.       merge_face_cache_element_data (w, findex, &cachel);
  1164.  
  1165.       return get_merged_face_element_index (w, &cachel);
  1166.     }
  1167. }
  1168.  
  1169.  
  1170. /*****************************************************************************
  1171.  interface functions
  1172.  ****************************************************************************/
  1173.  
  1174. /* #### This function should be converted into appropriate device methods. */
  1175. static void
  1176. update_EmacsFrame (Lisp_Object frame, Lisp_Object name)
  1177. {
  1178.   struct frame *frm = XFRAME (frame);
  1179.  
  1180. #ifdef HAVE_X_WINDOWS
  1181.   if (FRAME_IS_X (frm))
  1182.      {
  1183.        Arg av[10];
  1184.        int ac = 0;
  1185.      
  1186.        if (EQ (name, Qforeground))
  1187.      {
  1188.        Lisp_Object color = FACE_FOREGROUND (Vdefault_face, frame);
  1189.        XColor fgc;
  1190.  
  1191.        fgc = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (color));
  1192.        XtSetArg (av[ac], XtNforeground, (void *) fgc.pixel); ac++;
  1193.      }
  1194.        else if (EQ (name, Qbackground))
  1195.      {
  1196.        Lisp_Object color = FACE_BACKGROUND (Vdefault_face, frame);
  1197.        XColor bgc;
  1198.  
  1199.        bgc = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (color));
  1200.        XtSetArg (av[ac], XtNbackground, (void *) bgc.pixel); ac++;
  1201.  
  1202.        /* Really crappy way to force the modeline shadows to be
  1203.               redrawn.  But effective. */
  1204.        MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (frm);
  1205.        MARK_FRAME_CHANGED (frm);
  1206.      }
  1207.        else if (EQ (name, Qfont))
  1208.      {
  1209.        Lisp_Object font = FACE_FONT (Vdefault_face, frame);
  1210.  
  1211.        XtSetArg (av[ac], XtNfont,
  1212.              (void *) FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font)));
  1213.        ac++;
  1214.      }
  1215.        else
  1216.      abort ();
  1217.  
  1218.        XtSetValues (FRAME_X_TEXT_WIDGET (frm), av, ac);
  1219.  
  1220.        /* Setting the background clears the entire frame area
  1221.           including the toolbar so we force an immediate redraw of
  1222.           it. */
  1223.        if (EQ (name, Qbackground))
  1224.      MAYBE_DEVMETH (XDEVICE (frm->device), redraw_frame_toolbars, (frm));
  1225.  
  1226.        /* The intent of this code is to cause the frame size in
  1227.       characters to remain the same when the font changes, at the
  1228.       expense of changing the frame size in pixels.  It's not
  1229.       totally clear that this is the right thing to do, but it's
  1230.       not clearly wrong either.  */
  1231.        if (EQ (name, Qfont))
  1232.      {
  1233.        EmacsFrameRecomputeCellSize (FRAME_X_TEXT_WIDGET (frm));
  1234.        Fset_frame_size (frame,
  1235.                 make_number (frm->width),
  1236.                 make_number (frm->height),
  1237.                 Qnil);
  1238.      }
  1239.      }
  1240. #endif /* HAVE_X_WINDOWS */
  1241.  
  1242. #ifdef HAVE_NEXTSTEP
  1243.   if (FRAME_IS_NS (frm))
  1244.     {
  1245.       /* This code still needs to be written */
  1246.     }
  1247. #endif /* HAVE_NEXSTEP */
  1248. }
  1249.  
  1250. static void
  1251. update_EmacsFrames (Lisp_Object locale, Lisp_Object name)
  1252. {
  1253.   if (FRAMEP (locale))
  1254.     {
  1255.       update_EmacsFrame (locale, name);
  1256.     }
  1257.   else if (DEVICEP (locale))
  1258.     {
  1259.       Lisp_Object frm;
  1260.  
  1261.       FRAME_LOOP (frm, XDEVICE (locale))
  1262.     update_EmacsFrame (XCAR (frm), name);
  1263.     }
  1264.   else if (EQ (locale, Qglobal) || EQ (locale, Qfallback))
  1265.     {
  1266.       Lisp_Object dev, frm;
  1267.       
  1268.       DEVICE_AND_FRAME_LOOP (dev, frm)
  1269.     update_EmacsFrame (XCAR (frm), name);
  1270.     }
  1271. }
  1272.  
  1273. void
  1274. update_frame_face_values (struct frame *f)
  1275. {
  1276.   Lisp_Object frm = Qnil;
  1277.  
  1278.   XSETFRAME (frm, f);
  1279.   update_EmacsFrame (frm, Qforeground);
  1280.   update_EmacsFrame (frm, Qbackground);
  1281.   update_EmacsFrame (frm, Qfont);
  1282. }
  1283.  
  1284. void
  1285. face_property_was_changed (Lisp_Object face, Lisp_Object property,
  1286.                Lisp_Object locale)
  1287. {
  1288.   int default_face = EQ (face, Vdefault_face);
  1289.  
  1290.   /* If the locale could affect the frame value, then call
  1291.      update_EmacsFrames just in case. */
  1292.   if (default_face &&
  1293.       (EQ (property, Qforeground) ||
  1294.        EQ (property, Qbackground) ||
  1295.        EQ (property, Qfont)))
  1296.     update_EmacsFrames (locale, property);
  1297.  
  1298.   if (WINDOWP (locale))
  1299.     {
  1300.       MARK_FRAME_FACES_CHANGED (XFRAME (XWINDOW (locale)->frame));
  1301.     }
  1302.   else if (FRAMEP (locale))
  1303.     {
  1304.       MARK_FRAME_FACES_CHANGED (XFRAME (locale));
  1305.     }
  1306.   else if (DEVICEP (locale))
  1307.     {
  1308.       MARK_DEVICE_FRAMES_FACES_CHANGED (XDEVICE (locale));
  1309.     }
  1310.   else
  1311.     {
  1312.       Lisp_Object dev;
  1313.       
  1314.       DEVICE_LOOP (dev)
  1315.     MARK_DEVICE_FRAMES_FACES_CHANGED (XDEVICE (XCAR (dev)));
  1316.     }
  1317.   
  1318.   update_faces_inheritance (face, property);
  1319.   XFACE (face)->dirty = 1;
  1320. }
  1321.  
  1322. DEFUN ("copy-face", Fcopy_face, Scopy_face, 2, 6, 0,
  1323.   "Defines and returns a new face which is a copy of an existing one,\n\
  1324. or makes an already-existing face be exactly like another. LOCALE,\n\
  1325. TAG-SET, EXACT-P, and HOW-TO-ADD are as in `copy-specifier'.")
  1326.      (old_face, new_name, locale, tag_set, exact_p, how_to_add)
  1327.      Lisp_Object old_face, new_name, locale, tag_set, exact_p, how_to_add;
  1328. {
  1329.   struct Lisp_Face *fold, *fnew;
  1330.   Lisp_Object new_face = Qnil;
  1331.   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
  1332.  
  1333.   old_face = Fget_face (old_face);
  1334.  
  1335.   /* We GCPRO old_face because it might be temporary, and GCing could
  1336.      occur in various places below. */
  1337.   GCPRO4 (tag_set, locale, old_face, new_face);
  1338.   /* check validity of how_to_add now. */
  1339.   (void) decode_how_to_add_specification (how_to_add);
  1340.   /* and of tag_set. */
  1341.   tag_set = decode_specifier_tag_set (tag_set);
  1342.   /* and of locale. */
  1343.   locale = decode_locale_list (locale);
  1344.  
  1345.   new_face = Ffind_face (new_name);
  1346.   if (NILP (new_face))
  1347.     {
  1348.       Lisp_Object temp;
  1349.  
  1350.       CHECK_SYMBOL (new_name, 0);
  1351.  
  1352.       /* Create the new face with the same status as the old face. */
  1353.       temp = (NILP (Fgethash (old_face, Vtemporary_faces_cache, Qnil))
  1354.           ? Qnil
  1355.           : Qt);
  1356.  
  1357.       new_face = Fmake_face (new_name, Qnil, temp);
  1358.     }
  1359.  
  1360.   fold = XFACE (old_face);
  1361.   fnew = XFACE (new_face);
  1362.  
  1363.   Fcopy_specifier (fold->foreground, fnew->foreground, locale,
  1364.            tag_set, exact_p, how_to_add);
  1365.   Fcopy_specifier (fold->background, fnew->background, locale,
  1366.            tag_set, exact_p, how_to_add);
  1367.   Fcopy_specifier (fold->font, fnew->font, locale,
  1368.            tag_set, exact_p, how_to_add);
  1369.   Fcopy_specifier (fold->display_table, fnew->display_table, locale,
  1370.            tag_set, exact_p, how_to_add);
  1371.   Fcopy_specifier (fold->background_pixmap, fnew->background_pixmap,
  1372.            locale, tag_set, exact_p, how_to_add);
  1373.   Fcopy_specifier (fold->underline, fnew->underline, locale,
  1374.            tag_set, exact_p, how_to_add);
  1375.   Fcopy_specifier (fold->highlight, fnew->highlight, locale,
  1376.            tag_set, exact_p, how_to_add);
  1377.   Fcopy_specifier (fold->dim, fnew->dim, locale,
  1378.            tag_set, exact_p, how_to_add);
  1379.   Fcopy_specifier (fold->blinking, fnew->blinking, locale,
  1380.            tag_set, exact_p, how_to_add);
  1381.   Fcopy_specifier (fold->reverse, fnew->reverse, locale,
  1382.            tag_set, exact_p, how_to_add);
  1383.   /* #### should it copy the individual specifiers, if they exist? */
  1384.   fnew->plist = Fcopy_sequence (fold->plist);
  1385.  
  1386.   UNGCPRO;
  1387.  
  1388.   return new_name;
  1389. }
  1390.  
  1391.  
  1392. void
  1393. init_faces (void)
  1394. {
  1395.   if (!initialized)
  1396.     return;
  1397.  
  1398.   Vpermanent_faces_cache = make_lisp_hashtable (10, 0, 0, HASHTABLE_NONWEAK);
  1399.   Vtemporary_faces_cache = make_lisp_hashtable (0, 0, 0, HASHTABLE_WEAK);
  1400.  
  1401.   /* Create the default face now so we know what it is immediately. */
  1402.   Vdefault_face = Qnil; /* so that Fmake_face() doesn't set up a bogus
  1403.                default value */
  1404.   Vdefault_face = Fmake_face (Qdefault, build_string ("default face"),
  1405.                   Qnil);
  1406.  
  1407.   /* Now create and initialize the rest of the built-in faces. */
  1408.   call0_with_handler (Qreally_early_error_handler, Qinit_faces);
  1409.  
  1410.   /* If Fget_face signals an error bad, bad things are going to
  1411.      happen.  That should only be possible if someone decided to stop
  1412.      creating these faces in init-faces.  Bad, bad someone. */
  1413.   Vmodeline_face = Fget_face (Qmodeline);
  1414.   Vhighlight_face = Fget_face (Qhighlight);
  1415.   Vleft_margin_face = Fget_face (Qleft_margin);
  1416.   Vright_margin_face = Fget_face (Qright_margin);
  1417.  
  1418.   /* Provide some last-resort fallbacks to avoid utter fuckage if
  1419.      someone provides invalid values for the global specifications. */
  1420.   set_specifier_fallback (Fget (Vdefault_face, Qforeground, Qnil),
  1421.               list1 (Fcons (Qnil,
  1422.                     build_string ("black"))));
  1423.   set_specifier_fallback (Fget (Vdefault_face, Qbackground, Qnil),
  1424.               list1 (Fcons (Qnil,
  1425.                     build_string ("white"))));
  1426.  
  1427.   /* #### We may want to have different fallback values if NeXTstep
  1428.      support is compiled in. */
  1429. #ifdef HAVE_X_WINDOWS
  1430.   {
  1431.     char *fonts[30];
  1432.     int n = 0;
  1433.     Lisp_Object inst_list = Qnil;
  1434.  
  1435.     /* The same gory list from x-faces.el.
  1436.        (#### Perhaps we should remove the stuff from x-faces.el
  1437.        and only depend on this stuff here?  That should work.)
  1438.      */
  1439.     fonts[n++] = "-*-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-*";
  1440.     fonts[n++] = "-*-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-*";
  1441.     fonts[n++] = "-*-courier-*-r-*-*-*-120-*-*-*-*-iso8859-*";
  1442.     fonts[n++] = "-*-*-medium-r-*-*-*-120-*-*-m-*-iso8859-*";
  1443.     fonts[n++] = "-*-*-medium-r-*-*-*-120-*-*-c-*-iso8859-*";
  1444.     fonts[n++] = "-*-*-*-r-*-*-*-120-*-*-m-*-iso8859-*";
  1445.     fonts[n++] = "-*-*-*-r-*-*-*-120-*-*-c-*-iso8859-*";
  1446.     fonts[n++] = "-*-*-*-r-*-*-*-120-*-*-*-*-iso8859-*";
  1447.     fonts[n++] = "-*-*-medium-r-*-*-*-120-*-*-m-*-*-*";
  1448.     fonts[n++] = "-*-*-medium-r-*-*-*-120-*-*-c-*-*-*";
  1449.     fonts[n++] = "-*-*-*-r-*-*-*-120-*-*-m-*-*-*";
  1450.     fonts[n++] = "-*-*-*-r-*-*-*-120-*-*-c-*-*-*";
  1451.     fonts[n++] = "-*-*-*-r-*-*-*-120-*-*-*-*-*-*";
  1452.     fonts[n++] = "-*-*-*-*-*-*-*-120-*-*-*-*-*-*";
  1453.     fonts[n++] = "*";
  1454.  
  1455.     for (--n; n >= 0; --n)
  1456.       inst_list = Fcons (Fcons (list1 (Qx), build_string (fonts[n])),
  1457.              inst_list);
  1458.     set_specifier_fallback (Fget (Vdefault_face, Qfont, Qnil), inst_list);
  1459.   }
  1460. #else
  1461.   /* #### This assumes that a font of nil is an OK instantiator, which
  1462.      may not be the case. */
  1463.   set_specifier_fallback (Fget (Vdefault_face, Qfont, Qnil), Qnil);
  1464. #endif
  1465.   
  1466.   set_specifier_fallback (Fget (Vdefault_face, Qunderline, Qnil),
  1467.              list1 (Fcons (Qnil, Qnil)));
  1468.   set_specifier_fallback (Fget (Vdefault_face, Qhighlight, Qnil),
  1469.              list1 (Fcons (Qnil, Qnil)));
  1470.   set_specifier_fallback (Fget (Vdefault_face, Qdim, Qnil),
  1471.              list1 (Fcons (Qnil, Qnil)));
  1472.   set_specifier_fallback (Fget (Vdefault_face, Qblinking, Qnil),
  1473.              list1 (Fcons (Qnil, Qnil)));
  1474.   set_specifier_fallback (Fget (Vdefault_face, Qreverse, Qnil),
  1475.              list1 (Fcons (Qnil, Qnil)));
  1476. }
  1477.  
  1478. void
  1479. syms_of_faces (void)
  1480. {
  1481.   /* Qdefault defined in general.c */
  1482.   defsymbol (&Qmodeline, "modeline");
  1483.   defsymbol (&Qleft_margin, "left-margin");
  1484.   defsymbol (&Qright_margin, "right-margin");
  1485.  
  1486.   defsubr (&Sfacep);
  1487.   defsubr (&Sfind_face);
  1488.   defsubr (&Sget_face);
  1489.   defsubr (&Sface_name);
  1490.   defsubr (&Sface_ascent);
  1491.   defsubr (&Sface_descent);
  1492.   defsubr (&Sface_width);
  1493.   defsubr (&Sface_list);
  1494.   defsubr (&Sextent_face);
  1495.   defsubr (&Sset_extent_face);
  1496.   defsubr (&Smake_face);
  1497.   defsubr (&Scopy_face);
  1498.  
  1499.   defsymbol (&Qface, "face");
  1500.   defsymbol (&Qfacep, "facep");
  1501.   defsymbol (&Qforeground, "foreground");
  1502.   defsymbol (&Qbackground, "background");
  1503.   /* Qfont defined in general.c */
  1504.   defsymbol (&Qdisplay_table, "display-table");
  1505.   defsymbol (&Qbackground_pixmap, "background-pixmap");
  1506.   defsymbol (&Qunderline, "underline");
  1507.   /* Qhighlight, Qreverse defined in general.c */
  1508.   defsymbol (&Qdim, "dim");
  1509.   defsymbol (&Qblinking, "blinking");
  1510.  
  1511.   defsymbol (&Qinit_face_from_resources, "init-face-from-resources");
  1512.   defsymbol (&Qinit_global_faces, "init-global-faces");
  1513.   defsymbol (&Qinit_device_faces, "init-device-faces");
  1514.   defsymbol (&Qinit_frame_faces, "init-frame-faces");
  1515.   defsymbol (&Qinit_faces, "init-faces");
  1516. }
  1517.  
  1518. void
  1519. vars_of_faces (void)
  1520. {
  1521.   staticpro (&Vpermanent_faces_cache);
  1522.   Vpermanent_faces_cache = Qnil;
  1523.   staticpro (&Vtemporary_faces_cache);
  1524.   Vtemporary_faces_cache = Qnil;
  1525.  
  1526.   staticpro (&Vdefault_face);
  1527.   Vdefault_face = Qnil;
  1528.   staticpro (&Vmodeline_face);
  1529.   Vmodeline_face = Qnil;
  1530.   staticpro (&Vhighlight_face);
  1531.   Vhighlight_face = Qnil;
  1532.  
  1533.   staticpro (&Vleft_margin_face);
  1534.   Vleft_margin_face = Qnil;
  1535.   staticpro (&Vright_margin_face);
  1536.   Vright_margin_face = Qnil;
  1537. }
  1538.